﻿using System;
using System.ComponentModel.Composition;
using System.Linq;
using Caliburn.Micro;
using CoProjectModel;
using Coproject.ViewModels.Interfaces;
using IdeaBlade.Application.Framework.Core.Composition;
using IdeaBlade.Application.Framework.Core.Persistence;
using IdeaBlade.Core;

namespace Coproject.ViewModels
{
    /// <summary>
    /// View-First ViewModel for LoggingView. See LoggingView.xaml
    /// </summary>
    [Export("LoggingViewModel", typeof (ILoggingViewModel))]
    public class LoggingViewModel : PropertyChangedBase, ILoggingViewModel, IPartImportsSatisfiedNotification
    {
        /// <summary>
        /// Static Collection for TraceMessages
        /// </summary>
        private static BindableCollection<LocalTraceMessage> _traceMessages =
            new BindableCollection<LocalTraceMessage>();

        private readonly ILog _log;
        private readonly TraceSubscriber _subscriber;

        public LoggingViewModel()
        {
            _log = LogManager.GetLog(typeof (LoggingViewModel));
            _log.Info("Logging ViewModel started");

            //Ideablade's example of Silverlight logging
            //see, drc.ideablade.com/xwiki/bin/view/Documentation/code-sample-trace-viewer-silverlight
            _subscriber = new TraceSubscriber();
            _subscriber.Publish += subscriber_Publish;
            _subscriber.StartSubscription();
        }

        /// <summary>
        /// Handler to receive IdeaBlade's trace messages.
        /// Client only trace of course
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void subscriber_Publish(object sender, PublishEventArgs e)
        {
            //Write an IdeaBlade tracemessage to Caliburn.Micro logging, with an embedded identification key.
            string s = String.Format("[IdeaBladeID:{0}] {1} {2} {3} {4}", e.TraceMessage.Id,
                                     e.TraceMessage.Timestamp.ToString(),
                                     e.TraceMessage.UserName,
                                     e.TraceMessage.Source, e.TraceMessage.Message);
            _log.Info(s);
        }

        /// <summary>
        /// Method used in DesignMode
        /// Within VS2010, for an unknown reason, this is called 3 times!
        /// </summary>
        public void Start()
        {
            var tm = new LocalTraceMessage();
            tm.Id = 1;
            tm.Timestamp = DateTime.Now.ToString();
            tm.UserName = "AUserName";
            tm.Source = "Source";
            tm.Message = "Message";
            _traceMessages.Add(tm);
        }

        /// <summary>
        /// Instance Property for View Binding
        /// </summary>
        public BindableCollection<LocalTraceMessage> TraceMessages
        {
            get
            {
                var r =
                    new BindableCollection<LocalTraceMessage>(
                        _traceMessages.OrderByDescending(x => x.Id).DefaultIfEmpty().ToList());
                return r;
            }
            set
            {
                _traceMessages = value;
                NotifyOfPropertyChange(() => TraceMessages);
            }
        }

        private static int _count;

        /// <summary>
        /// Handler to receive Caliburn.Micro Logging messages
        /// </summary>
        /// <param name="source"></param>
        /// <param name="message"></param>
        public static void LogMethod(string source, string message)
        {
            string user = "";
            if (IoCAllowed)
            {
                var emp =
                    CompositionHelper.GetInstance(typeof (IEntityManagerProvider<CoProjectEntities>), "",
                                                  CreationPolicy.Shared) as IEntityManagerProvider<CoProjectEntities>;
                if (emp.Manager.Principal != null)
                {
                    user = emp.Manager.Principal.Identity.Name;
                }
                else
                    user = "<server:null>";
            }
            else
                user = "<unknown>";

            _count++;

            //Use a key to identify IdeaBlade messages and create a psuedo source.
            string src = "";
            if (message.Contains("IdeaBladeID:"))
                src = "IdeaBlade";
            else
                src = source;

            var m = new LocalTraceMessage();
            m.Id = _count;
            m.Timestamp = DateTime.Now.ToString();
            m.UserName = user;
            m.Source = src;
            m.Message = message;

            _traceMessages.Add(m);

            if (IoCAllowed)
            {
                object vm = CompositionHelper.GetInstance(typeof (ILoggingViewModel), "LoggingViewModel",
                                                          CreationPolicy.Shared);
                if (vm != null)
                {
                    var lvm = vm as LoggingViewModel;
                    lvm.TraceMessages = _traceMessages;
                }
            }
        }

        private static bool IoCAllowed;

        public void OnImportsSatisfied()
        {
            IoCAllowed = true;
        }

        #region Send Logging to IdeaBlade Server

#if false

        public void SendMessageToServer(object msg)
        {
            //Uncomment to send messages to server
            //this.LogToServer((msg as LocalTraceMessage).ToString());
        }

        //Send to Serverside Method.
        //See www.ideablade.com/forum/forum_posts.asp?TID=1481&title=writing-to-server-debug-log-from-client
        //Messages will be logged into log\DebugLog.xml in the CoProjectDF.web project
        //It does work but noticably slows the application down, and the
        //resultant messages are out of order - see Id.
        //Initial messages are lost as the client and server need to initialise.
        private void LogToServer(string message)
        {
            var io = _emp.Manager.InvokeServerMethodAsync(
                                  "CustomLogging.ServerLogger,CoProjectModel", // Assembly-qualified name for the server class
                                  "Log", // name of the server method
                                  (e) =>
                                  {
                                      var a = e.CompletedSuccessfully;
                                  },
                                  null, // state object to identify this particular call (we don't care)
                                  message);
        }
#endif

        #endregion
    }

    /// <summary>
    /// Used to translate Ideablade and Caliburn tracemessages into
    /// a common format to display in grid.
    /// </summary>
    public class LocalTraceMessage
    {
        public int Id { get; set; }
        public string Timestamp { get; set; }
        public string UserName { get; set; }
        public string Source { get; set; }
        public string Message { get; set; }
    }
}